package com.yixing.tech.entity.service;

import com.yixing.tech.common.base.BaseResponse;
import com.yixing.tech.common.base.BusinessException;
import com.yixing.tech.common.base.ConditionsVO;
import com.yixing.tech.common.enums.YesOrNo;
import com.yixing.tech.entity.entity.CustomActionParam;
import com.yixing.tech.entity.po.EntityData;
import com.yixing.tech.entity.po.Obj;
import com.yixing.tech.common.utils.ExcelUtil;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author yixing tech
 * at 2022/04/08
 * describe：
 */
@Service
@Slf4j
public class CustomActuator implements ICustomActuator {

    @Resource
    MongoTemplate mongoTemplate;
    @Autowired
    private EntityBaseService entityBaseService;
    @Resource
    IEntityService entityService;

    @Override
    public Object customAction(HttpServletResponse response, CustomActionParam param) throws Exception {
        String method = param.getMethod();
        if (method.startsWith("setParam")) {
            set(param);
            return false;
        } else if (method.startsWith("callAction")) {
            callAction(param);
            return false;
        } else {
            switch (method) {
                case "set":
                    set(param);
                    return false;
                case "exportProdDetail":
                    entityService.exportProdDetail(response, param.getEntityId());
                    return true;
                case "buildBomRQOrderByProdInStockId":
                    entityService.buildBomRQOrderByProdInStockId(param.getEntityId(), param.getUserVO());
                    return false;
                case "lookDetail":
                    Map data = new HashMap();
                    data.put("obj", mongoTemplate.findById("6513970571364d4bd48773e5", Obj.class));
                    data.put("content", orderInOutDetail(param));
                    return data;
                case "exportDetail":
                    ExcelUtil.exportToExcel(response, "备料计划明细.xls", orderInOutDetail(param));
                    return true;
                case "importExcel":
                    // 子表单导入
                    // 参数要求： 1. 文件， 2： attrName：属性名称
                    List<Map<String, Object>> list = ExcelUtil.excelToList(param.getFile(), null);
                    if(CollectionUtils.isEmpty(list)) {
                        throw new BusinessException("文件中无数据无需导入");
                    }
                    String tableName = param.getEntityId();
                    String updateId = param.getObjCode();
                    String attrName = Optional.ofNullable(param.getArgs().get("attrName")).map(String::valueOf).orElse(null);
                    if(!StringUtils.hasLength(attrName)) {
                        throw new BusinessException("导入失败，未找到对应的子表单字段");
                    }
                    Document document = mongoTemplate.findById(new ObjectId(updateId), Document.class, tableName);
                    if(document == null) {
                        throw new BusinessException("导入失败，数据不存在");
                    }
                    Update update = new Update();
                    List<Map> subformList = document.getList(attrName, Map.class);
                    if(subformList == null) {
                        subformList = new LinkedList<>();
                    }
                    subformList.addAll(list);
                    update.set(attrName, subformList);
                    mongoTemplate.updateFirst(Query.query(Criteria.where("_id").is(new ObjectId(updateId))), update, tableName);
                    return true;
                case "cancelGraphiteBoat":
                    String entityId = param.getEntityId();
                    String objectId = param.getObjCode();
                    Map<String, Object> args = param.getArgs();
                    String tableId = args.get("tableId").toString();
                    entityService.cancelGraphiteBoat(objectId, tableId, entityId);
                    return false;
//                case "exportDeviceSpotCheckDetail":
//                    entityService.exportDeviceSpotCheckDetail(response, param);
//                    return true;
                case "clearAlarm":
                    entityService.clearAlarm(param.getObjCode(),param.getEntityId());
                    return true;
                case "lookOrderSummary":
                    return entityService.lookOrderSummary(param);
                case "exportSingleProdDetail":
                    entityService.singleExportProdDetail(response, param.getEntityId());
                    return true;
                default:
            }
        }

        return false;

    }


    /**
     * 订单物料进出明细
     *
     * @param param
     * @return
     * @throws BusinessException
     */
    private List<Map> orderInOutDetail(CustomActionParam param) throws BusinessException {
        String entityId = param.getEntityId();
        Document order = entityBaseService.getEntity(param.getObjCode(), entityId, null, false);
        List<Document> mList = order.getList("物料清单", Document.class);
        List<Map> materialList = new ArrayList<>();
        //获取bom领料数据
        ConditionsVO cond = new ConditionsVO();
        List<ConditionsVO.Condition> cList = new ArrayList<>();
        cond.setConditions(cList);
        ConditionsVO.Condition con1 = new ConditionsVO.Condition();
        cList.add(con1);
        con1.setKey("所属备料计划单.id");
        con1.setSymbol("is");
        con1.setValue(new ObjectId(entityId));
        ConditionsVO.Condition con2 = new ConditionsVO.Condition();
        cList.add(con2);
        con2.setKey("状态");
        con2.setSymbol("is");
        con2.setValue("完成");
        List<Document> lyList = entityBaseService.list(cond, "64c725d64d1a5541d57a186f", null);
        //获取bom退料数据
        con1.setKey("领料单.id");
        con1.setSymbol("in");
        con1.setValue(lyList.stream().map(m -> m.getString("id")).collect(Collectors.toList()));
        List<Document> tyList = entityBaseService.list(cond, "64c7532c4d1a5541d57a1885", null);
        //累计剩余
        con1.setKey("物料");
        con1.setSymbol("in");
        con1.setValue(mList.stream().map(m -> m.getString("材料编码")).collect(Collectors.toList()));
        con2.setKey("数量");
        con2.setSymbol("gt");
        con2.setValue(0);
        List<Document> syList = entityBaseService.list(cond, "64e1b2c3ed614b463d719eae", null);
        //获取bom下发数据
        con1.setKey("所属备料计划单.id");
        con1.setSymbol("is");
        con1.setValue(new ObjectId(entityId));
        con2.setKey("是否已同步");
        con2.setSymbol("is");
        con2.setValue(true);
        ConditionsVO.Condition con3 = new ConditionsVO.Condition();
        cList.add(con3);
        con3.setKey("是否已冲销");
        con3.setSymbol("ne");
        con3.setValue(true);
        List<Document> xfList = entityBaseService.list(cond, "64c7642c2521ce161ab7762b", null);
        //获取生产退库数据
        cList.clear();
        cList.add(con1);
        cList.add(con2);
        con1.setKey("所属备料计划单.id");
        con1.setSymbol("is");
        con1.setValue(new ObjectId(entityId));
        con2.setKey("是否已同步");
        con2.setSymbol("is");
        con2.setValue(true);
        List<Document> xftlList = entityBaseService.list(cond, "6501593a8993655718f95d56", null);
        String orderNo = order.getString("来源单据号");
        Criteria criteria =Criteria.where("isDelete").ne(YesOrNo.YES.ordinal())
                .and("工单编号").is(orderNo);
//        Document orderInfo = mongoTemplate.findOne(new Query(criteria), Document.class, "entity_64c1d1b6fb1d976ceaff0cfc");
//        if (orderInfo == null) {
//            throw new BusinessException(-1, "订单不存在!");
//        }
//
//        //生产订单主键
//        String orderId = orderInfo.get("id").toString();
//        Double inProductWareHouseNum = entityService.getInProductWareHouseNum(orderId);
//        Double inFragmentWareHouseNum = entityService.getInFragmentWareHouseNum(orderId);
      //  Map<String, Double> ylNumMap = entityService.getYlNum(entityId);
        for (Document d : mList) {
            Map map = new HashMap();
            map.put("材料编码", d.getString("材料编码"));
            map.put("材料名称", d.getString("材料名称"));
            map.put("规格", d.getString("规格"));
            map.put("计划出库数量", d.getString("计划出库数量"));
            map.put("工单号", orderNo);
            materialList.add(map);
            double lyCount = lyList.stream().map(m -> m.getList("物料清单", Document.class)).flatMap(Collection::stream).filter(f -> f.getString("编码").equals(d.getString("材料编码"))).mapToDouble(m -> Double.parseDouble(m.get("数量").toString())).sum();
            map.put("累计领料", lyCount);
            double tyCount = tyList.stream().map(m -> m.getList("物料清单", Document.class)).flatMap(Collection::stream).filter(f -> f.get("物料类型", Document.class).getString("物料").equals(d.getString("材料编码"))).mapToDouble(m -> Double.parseDouble(m.get("数量").toString())).sum();
            map.put("累计退库", tyCount);
            double syCount = syList.stream().filter(f -> f.getString("物料").equals(d.getString("材料编码"))).mapToDouble(m -> Double.parseDouble(m.get("数量").toString())).sum();
            map.put("累计剩余", syCount);
            double xfCount = xfList.stream().map(m -> m.getList("物料清单", Document.class)).flatMap(Collection::stream).filter(f -> f.getString("编码").equals(d.getString("材料编码"))).mapToDouble(m -> Double.parseDouble(m.get("数量").toString())).sum();
            map.put("累计下发", xfCount);
            double xftlCount = xftlList.stream().map(m -> m.getList("物料清单", Document.class)).flatMap(Collection::stream).filter(f -> f.getString("编码").equals(d.getString("材料编码")) && f.get("退回数量") != null).mapToDouble(m -> Double.parseDouble(m.get("退回数量").toString())).sum();
            map.put("累计生产退料", xftlCount);
//            map.put("成品产出", inProductWareHouseNum);
//            map.put("碎片产出", inFragmentWareHouseNum);
//            map.putAll(ylNumMap);
        }
        return materialList;
    }

    /**
     * 领料限制约束
     */
    List<Map> constraintList = new ArrayList<>();

    {
        Map<String, Object> map = new HashMap<>();
        map.put("材料分类", "硅片");
        map.put("材料编码", "1101");
        map.put("数量", 0);
        constraintList.add(map);
        Map<String, Object> map1 = new HashMap<>();
        map1.put("材料分类", "浆料");
        map1.put("材料编码", "1102");
        map1.put("数量", 0);
        constraintList.add(map1);
        Map<String, Object> map2 = new HashMap<>();
        map2.put("材料分类", "网板");
        map2.put("材料编码", "1103");
        map2.put("数量", 0);
        constraintList.add(map2);
        Map<String, Object> map3 = new HashMap<>();
        map3.put("材料分类", "化学品");
        map3.put("材料编码", "1104");
        map3.put("数量", 0);
        constraintList.add(map3);
        Map<String, Object> map4 = new HashMap<>();
        map4.put("材料分类", "气体");
        map4.put("材料编码", "1105");
        map4.put("数量", 0);
        constraintList.add(map4);
        Map<String, Object> map5 = new HashMap<>();
        map5.put("材料分类", "包材");
        map5.put("材料编码", "12");
        map5.put("数量", 0);
        constraintList.add(map5);
    }

    /**
     * 调用三方
     *
     * @param param
     * @throws BusinessException
     */
    @Override
    public void callAction(CustomActionParam param) throws BusinessException {
        String method = param.getMethod();
        BaseResponse response = null;
        switch (method) {
            case "callActionDiscard":
                Document data = mongoTemplate.findById(new ObjectId(param.getEntityId()), Document.class, "entity_" + param.getObjCode());
                List<String> itemStrs = new ArrayList<>();
                try {
                    itemStrs = data.getList("成品列表", String.class);
                } catch (Throwable e) {
                    // 兼容
                    List<ObjectId> lId = data.getList("成品列表", ObjectId.class);
                    if(!CollectionUtils.isEmpty(lId)) {
                        itemStrs = lId.stream().map(x -> x.toString()).collect(Collectors.toList());
                    }
                }
                List<Pair<Query, Update>> list1 = new ArrayList<>();
                BulkOperations operations = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, "entity_64bf6f57558136382dc87f79");
                for (String i : itemStrs) {
                    Query query = Query.query(Criteria.where("_id").is(new ObjectId(i)));
                    Update update1 = new Update();
                    update1.set("是否已出库", false);
                    update1.set("是否出库中", false);
                    update1.set("出库单号", null);
                    Pair<Query, Update> pair = Pair.of(query, update1);
                    list1.add(pair);
                }
                operations.upsert(list1);
                operations.execute();
                break;
            default:
        }
        if (response!=null && !response.isOk()) {
            BusinessException exception = new BusinessException(-1, response.getDesc());
            throw exception;
        }
    }

    /**
     * 通用修改属性行为
     *
     * @param param
     * @throws BusinessException
     */
    private void set(CustomActionParam param) throws BusinessException {
        Map<String, Object> args = param.getArgs();
        if (ObjectUtils.isEmpty(args)) return;
        EntityData entity = new EntityData();
        entity.putAll(args);
        entity.put("id", param.getEntityId());
        entityBaseService.updateEntity(param.getObjCode(), entity);
    }

}









